"""
Course Model Module

Defines course-related data models, including:
- Course class: represents basic course information
- Course relationship management with Student and Teacher
"""

from typing import Dict, List, Optional, Any
from datetime import datetime
import json


class Course:
    """Course class - represents a course"""
    
    def __init__(self, course_id: str, name: str, description: str, teacher_id: str, 
                 max_students: int = 50, instructor_name: str = "", credits: int = 2, is_active: bool = True,
                 schedule: str = "TBD", location: str = "TBD"):
        """
        Initialize course object
        
        Parameters:
            course_id: Course unique identifier
            name: Course name
            description: Course description
            teacher_id: Instructor ID
            max_students: Maximum number of students, default 50
            instructor_name: Instructor name, default empty string
            credits: Credits, default 2
            is_active: Whether active, default True
        """
        self.course_id = course_id
        self.name = name
        self.description = description
        self.teacher_id = teacher_id
        self.max_students = max_students
        self.instructor_name = instructor_name
        self.credits = credits
        self.is_active = is_active
        self.schedule = schedule
        self.location = location
        self.student_ids: List[str] = []  # List of student IDs enrolled in the course
        self.created_at = datetime.now()
        self.updated_at = None  # updated_at is None when created, only set when actually updated
    
    def add_student(self, student_id: str) -> bool:
        """
        Add student to course
        
        Parameters:
            student_id: Student ID
            
        Returns:
            Whether addition was successful
        """
        if student_id in self.student_ids:
            return False  # Student already in course
        
        if self.is_full():
            return False  # Course is full
        
        self.student_ids.append(student_id)
        self.updated_at = datetime.now()
        return True
    
    def remove_student(self, student_id: str) -> bool:
        """
        Remove student from course
        
        Parameters:
            student_id: Student ID
            
        Returns:
            Whether removal was successful
        """
        if student_id not in self.student_ids:
            return False  # Student not in course
        
        self.student_ids.remove(student_id)
        self.updated_at = datetime.now()
        return True
    
    def is_full(self) -> bool:
        """
        Check if course is full
        
        Returns:
            Whether course is full
        """
        return len(self.student_ids) >= self.max_students
    
    def get_student_count(self) -> int:
        """
        Get number of students in course
        
        Returns:
            Number of students
        """
        return len(self.student_ids)
    
    # Add getter methods to be compatible with CLI calls
    def get_id(self) -> str:
        """Get course ID"""
        return self.course_id
    
    def get_name(self) -> str:
        """Get course name"""
        return self.name
    
    def get_description(self) -> str:
        """Get course description"""
        return self.description
    
    def get_teacher_id(self) -> str:
        """Get teacher ID"""
        return self.teacher_id
    
    def get_max_students(self) -> int:
        """Get maximum number of students"""
        return self.max_students
    
    def get_current_students(self) -> int:
        """Get current number of students"""
        return len(self.student_ids)
    
    def get_credits(self) -> int:
        """Get credits"""
        return self.credits
    
    def get_schedule(self) -> str:
        """Get class schedule"""
        return self.schedule
    
    def get_location(self) -> str:
        """Get class location"""
        return self.location
    
    def get_created_at(self) -> datetime:
        """Get creation time"""
        return self.created_at
    

    
    def to_dict(self) -> Dict[str, Any]:
        """
        Convert course object to dictionary

        Returns:
            Dictionary representation of course data
        """
        return {
            "course_id": self.course_id,
            "name": self.name,
            "description": self.description,
            "teacher_id": self.teacher_id,
            "max_students": self.max_students,
            "instructor_name": self.instructor_name,
            "credits": self.credits,
            "is_active": self.is_active,
            "schedule": self.schedule,
            "location": self.location,
            "student_ids": self.student_ids,
            "created_at": self.created_at.isoformat(),
            "updated_at": self.updated_at.isoformat() if self.updated_at else None
        }
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'Course':
        """
        Create course object from dictionary
        
        Parameters:
            data: Dictionary representation of course data
            
        Returns:
            Course object
        """
        course = cls(
            course_id=data["course_id"],
            name=data["name"],
            description=data["description"],
            teacher_id=data["teacher_id"],
            max_students=data["max_students"],
            instructor_name=data.get("instructor_name", ""),
            credits=data.get("credits", 3),
            is_active=data.get("is_active", True)
        )
        
        course.student_ids = data.get("student_ids", [])
        course.created_at = datetime.fromisoformat(data["created_at"])
        course.updated_at = datetime.fromisoformat(data["updated_at"]) if data.get("updated_at") else None
        
        return course
    
    def __str__(self) -> str:
        """
        String representation
        
        Returns:
            String representation of course information
        """
        return f"{self.course_id} - {self.name} ({self.get_student_count()}/{self.max_students})"
    
    def __repr__(self) -> str:
        """
        Detailed string representation
        
        Returns:
            Detailed string representation of course information
        """
        return (f"Course(course_id='{self.course_id}', name='{self.name}', "
                f"teacher_id='{self.teacher_id}', "
                f"students={self.get_student_count()}/{self.max_students})")
